package com.gree.elasticsearch.security;

import com.gree.elasticsearch.security.filter.CustomerUsernameAndPasswordAuthenticationFilter;
import com.gree.elasticsearch.security.filter.JwtAuthenticationFilter;
import com.gree.elasticsearch.security.filter.UrlFilter;
import com.gree.elasticsearch.security.provider.JwtAuthenticationProvider;
import com.gree.elasticsearch.security.provider.UsernameAndPasswordAuthenticationProvider;
import com.gree.elasticsearch.security.requestmatcher.SkipRequestMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private LocalAuthenticationEntryPoint localAuthenticationEntryPoint;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    private JwtAuthenticationProvider jwtAuthenticationProvider;

    @Autowired
    private UsernameAndPasswordAuthenticationProvider usernameAndPasswordAuthenticationProvider;

    private List<String> skipUriGroup;

    private String jwtAuthenticationFilterProcessUri ;

    @Autowired
    private UrlFilter urlFilter;

    private JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        String[] skipUris = new String[]{"/api/authentication"};
        jwtAuthenticationFilterProcessUri = "/api/**";
        skipUriGroup = Arrays.asList(skipUris);
        SkipRequestMatcher skipRequestMatcher = new SkipRequestMatcher(skipUriGroup, jwtAuthenticationFilterProcessUri);
        JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationFailureHandler, skipRequestMatcher);
        jwtAuthenticationFilter.setAuthenticationManager(this.authenticationManager());

        return jwtAuthenticationFilter;
    }

    private CustomerUsernameAndPasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
        CustomerUsernameAndPasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new CustomerUsernameAndPasswordAuthenticationFilter(authenticationFailureHandler, authenticationSuccessHandler);
        usernamePasswordAuthenticationFilter.setAuthenticationManager(this.authenticationManager());

        return usernamePasswordAuthenticationFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().disable()
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/api/authentication")
                .permitAll()
                .antMatchers("/api/**").authenticated()
                .anyRequest().permitAll();
        http.exceptionHandling().authenticationEntryPoint(localAuthenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);
        http.addFilterAt(urlFilter, UsernamePasswordAuthenticationFilter.class);
        http.addFilterAfter(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(usernameAndPasswordAuthenticationProvider);
        auth.authenticationProvider(jwtAuthenticationProvider);
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        AuthenticationManager authenticationManager = super.authenticationManager();
        return authenticationManager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12);
        return passwordEncoder;
    }

    public static void main(String[] args) {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(12);
        String res = passwordEncoder.encode("123456");
        System.out.printf(res);
        UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter;
    }
}
